home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
interval.lha
/
interval
/
interval.c
next >
Wrap
C/C++ Source or Header
|
1989-10-31
|
5KB
|
193 lines
// This software is in the public domain.
// Permission is granted to use this software for any
// purpose commercial or non-commercial.
// The implementer/distributer assume no liability for
// any damages, incidental, consequential or otherwise,
// arising from the use of this software.
// Implementation of class interval
//
// Most operators are trivial and could be inlined.
//
// Multiply is more interesting. The complicated testing
// may be more time consuming than the floating-point
// operations it attempts to avoid.
// How could this testing be streamlined?
//
// Note that divide blurts out error/warning messages using fprintf :-(
// Strictly speaking, division is undefined if the divisor interval
// contains zero. This code is sloppy in allowing it, but it warns.
//
// No attempt is made to control rounding so accuracy is dubious.
//
// No attempt is made to detect/recover from overflow or underflow.
// This is a serious deficiency. Is there a 'portable' around it?
#include <CC/stdio.h>
#include "interval.h"
interval interval::operator+(interval I)
{
interval temp(lo_bound, hi_bound);
return temp += I;
}
interval interval::operator-(interval I)
{
interval temp(lo_bound, hi_bound);
return temp -= I;
}
interval interval::operator*(interval I)
{
interval temp(lo_bound, hi_bound);
return temp *= I;
}
interval interval::operator/(interval I)
{
interval temp(lo_bound, hi_bound);
return temp /= I;
}
interval &interval::operator+=(interval I)
{
lo_bound += I.lo_bound;
hi_bound += I.hi_bound;
return *this;
}
interval &interval::operator-=(interval I)
{
lo_bound -= I.lo_bound;
hi_bound -= I.hi_bound;
return *this;
}
// Multiply is a bit complicated.
// A naive version simply takes the minimum of all combinations
// as the new lo_bound and the maximum as the new hi_bound.
// But this involves four double precision floating multiples.
// A quick examination of the signs of the intervals reveals
// that there are nine possible cases of which only one
// requires all four multiplications. The other cases only
// require two multiplications. We assume that it is faster to
// compute and dispatch to the right case than to perform
// the extra multiplies. If not, use the naive scheme.
//
// The cases can be described as follows:
// Each interval is either non-negative (lo bound >= 0),
// non-positive (hi bound <= 0), or crosses(includes) zero,
// including some numbers on either side.
// If we label the intervals, A and B, corresponding to
// "this" and "I", we get the following matrix:
//
// Bcross Bnonneg Bnonpos
//
// Across
//
// Anonneg
//
// Anonpos
interval &interval::operator*=(interval I)
{
enum possibility {
AcrossBcross, AcrossBnn, AcrossBnp,
AnnBcross, AnnBnn, AnnBnp,
AnpBcross, AnpBnn, AnpBnp
} choice;
if (lo_bound >= 0.0) choice = AnnBcross;
else if (hi_bound <= 0.0) choice = AnpBcross;
else choice = AcrossBcross;
if (I.lo_bound >= 0.0) choice += 1;
else if (I.hi_bound <= 0.0) choice += 2;
switch (choice)
{
case AcrossBcross: {
double HL = hi_bound*I.lo_bound,
HH = hi_bound*I.hi_bound,
LL = lo_bound*I.lo_bound,
LH = lo_bound*I.hi_bound;
lo_bound = HL<LH?HL:LH;
hi_bound = LL>HH?LL:HH;
}
break;
case AcrossBnn:
lo_bound *= I.hi_bound;
hi_bound *= I.hi_bound;
break;
case AcrossBnp: {
double new_hi_bound = lo_bound * I.lo_bound;
lo_bound = hi_bound*I.lo_bound;
hi_bound = new_hi_bound;
}
break;
case AnnBcross:
lo_bound = hi_bound*I.lo_bound;
hi_bound *= I.hi_bound;
break;
case AnnBnn:
lo_bound *= I.lo_bound;
hi_bound *= I.hi_bound;
break;
case AnnBnp: {
double new_hi_bound = lo_bound * I.hi_bound;
lo_bound = hi_bound*I.lo_bound;
hi_bound = new_hi_bound;
}
break;
case AnpBcross:
hi_bound = lo_bound*I.lo_bound;
lo_bound *= I.hi_bound;
break;
case AnpBnn:
lo_bound *= I.hi_bound;
hi_bound *= I.lo_bound;
break;
case AnpBnp: {
double new_hi_bound = lo_bound * I.lo_bound;
lo_bound = hi_bound*I.hi_bound;
hi_bound = new_hi_bound;
}
break;
default:
fprintf(stderr,
"Bad interval (low bound > hi bound) [%f, %f] * [%f, %f]\n",
lo_bound, hi_bound, I.lo_bound, I.hi_bound);
lo_bound = hi_bound = 0.0;
break;
}
return *this;
}
interval &interval::operator/=(interval I)
{
if (I.lo_bound == 0.0 && I.hi_bound == 0)
fprintf(stderr, "Error: Division by zero attempted - [%f,%f]/[f,%f]\n",
lo_bound, hi_bound, I.lo_bound, I.hi_bound);
else {
if (I.lo_bound < 0 && I.hi_bound > 0)
fprintf(stderr, "Warning: Division by zero possible - [%f,%f]/[%f,%f]\n",
lo_bound, hi_bound, I.lo_bound, I.hi_bound);
interval inv(1.0/I.lo_bound, 1.0/I.hi_bound);
return inv *= *this;
}
}